/**************************************************************/
/*  This file is licensed from, and is a trade secret of:     */
/*                                                            */
/*    Mercury Computer Systems, Incorporated                  */
/*    199 Riverneck Road                                      */
/*    Chelmsford, Massachusetts 01824-2820                    */
/*    United States of America                                */
/*    Telephone + 1 978 256-1300                              */
/*                                                            */
/*  Refer to your Software License Agreement for provisions   */
/*  on use, duplication, or disclosure.                       */
/*  US. Government users and prime contractors are also       */
/*  governed by the following Data Rights Notice:             */
/*  Use, duplication or disclosure by the US. Government is   */
/*  subject to the provisions set forth in FAR 52.227-14 for  */
/*  restricted rights or other agency data rights provisions  */
/*  on commercial software and documentation, as applicable.  */
/*                                                            */
/*  This file: (a) was developed at private expense, and no   */
/*  part was developed with government funds, (b) is a        */
/*  trade secret of Mercury Computer Systems, Inc. for the    */
/*  purposes of the Freedom of Information Act, (c) is        */
/*  "commercial computer software" subject to limited         */
/*  utilization as provided in the above noted Software       */
/*  License Agreement and (d) is in all respects data         */
/*  belonging exclusively to Mercury Computer Systems, Inc..  */
/*                                                            */
/**************************************************************/

/******************************************************************/
/* Copyright (c) 1999-2003, Mercury Computer Systems, Inc.,       */
/* Chelmsford MA.,and all third party embedded software sources.  */
/* All rights reserved under the Copyright laws of US. and        */
/* international treaties.                                        */
/*                                                                */
/* Patent Pending                                                 */
/******************************************************************/


//$COPYRIGHT_END


#ifdef WIN32
#pragma warning(disable: 4786)
#endif

#include <tao/corba.h>
#include <iostream>
#include <vector>
#include <sstream>
#include <cstring>

#include "CF__PropertySet_impl.h"

using namespace std;

CF__PropertySet_impl::CF__PropertySet_impl (const CF::Properties & configProperties)
  : m_initialized (false)
{
  m_my_orb = CORBA::ORB::_nil ();
  InitProperties (configProperties);
}

CF__PropertySet_impl::CF__PropertySet_impl ()
  : m_initialized (false)
{
  m_my_orb = CORBA::ORB::_nil ();
}

CF__PropertySet_impl::~CF__PropertySet_impl ()
{
}

// Helper function.
static
void
AppendProperty (CF::Properties & props, const CF::DataType & prop)
{
  int old_length = props.length();
  props.length (old_length+1);
  props[old_length] = prop;
}

// Simple, minimally error checking implementation.
void
CF__PropertySet_impl::configure (const CF::Properties & configProperties)
  throw (CORBA::SystemException, CF::PropertySet::InvalidConfiguration,
	 CF::PropertySet::PartialConfiguration)
{
  unsigned long ii, jj;
  CF::Properties invalidProperties;
  bool error = false;
  bool some_success = false;

  if (!m_initialized) {
#ifdef MCS_VERBOSE
    cout << "CF__PropertySet_impl: Initializing properties." << endl;
#endif
    InitProperties (configProperties);
    return;
  }

#ifdef MCS_VERBOSE
  cout << "CF__PropertySet_impl: Configuring properties." << endl;
#endif

  for (ii=0; ii < configProperties.length(); ++ii) {
    bool match = false;

    for (jj=0; jj < m_props.length(); ++jj) {
      CF::DataType & prop = m_props[jj];

      // Look for a property whose name matches the specified property.
      if (strcmp (prop.id, configProperties[ii].id) == 0) {
	// See if the specified property type matches.
	CORBA::TypeCode_var spec_type = configProperties[ii].value.type ();
	CORBA::TypeCode_var local_type = prop.value.type ();

	if (spec_type->kind() == local_type->kind()) {
	  match = true;
	  prop.value = configProperties[ii].value;
	  some_success = true;
	}
      } // if name compare
    } // for this-> properties loop

    // If we couldn't find the specified property, log error
    if (!match) { // Property not found.
      // Add this property to invalid list
      error = true;
      AppendProperty (invalidProperties, configProperties[ii]);
    }
  } // for input properties loop

  // Throw one of 2 exceptions, depending on whether we had some success.
  if (error) {
    if (some_success) {
      CF::PropertySet::PartialConfiguration prop_ex;
      prop_ex.invalidProperties = invalidProperties;
      throw prop_ex;
    }
    else {
      CF::PropertySet::InvalidConfiguration prop_ex;
      prop_ex.invalidProperties = invalidProperties;
      throw prop_ex;
    }
  }
}  // End of configure

void
CF__PropertySet_impl::query (CF::Properties & configProperties)
  throw (CORBA::SystemException, CF::UnknownProperties)
{
  unsigned long ii, jj;

  if (configProperties.length() == 0){
    int old_length = 0;
    for (jj=0; jj<m_props.length(); ++jj) {
      CF::DataType & prop = m_props[jj];
      configProperties.length (old_length+1);
      configProperties[old_length] = prop;
      old_length++;
    }
  }
  else {
    CF::Properties invalidProperties;
    bool error = false;

    for (ii=0; ii<configProperties.length(); ++ii) {
      bool match = false;

      for (jj=0; jj<m_props.length(); ++jj) {
	CF::DataType & prop = m_props[jj];

	// look for a property whose name matches the specified property.
	if (strcmp (prop.id, configProperties[ii].id) == 0) {
	  match = true;
	  configProperties[ii].value = prop.value;
	} // if name compare
      } // for this-> properties loop

      // If we couldn't find the specified property, log error.
      if (!match) { // specified property name not found
	error = true;
	AppendProperty (invalidProperties, configProperties[ii]);
      }
    } // for input properties loop

    if (error) {
      CF::UnknownProperties prop_ex;
      prop_ex.invalidProperties = invalidProperties;
      throw prop_ex;
    }
  }
} // End of query.


void
CF__PropertySet_impl::InitProperties (const CF::Properties & configProperties)
{
  m_props = configProperties;
  m_initialized = true;

  // Construct private property map.
  unsigned int ii;
  for (ii=0; ii<m_props.length(); ++ii) {
    string temp_id (m_props[ii].id);
    m_property_index_mapping[temp_id] = ii;
  }
}

void
CF__PropertySet_impl::InitOrb (CORBA::ORB_ptr the_orb)
{
  m_my_orb = CORBA::ORB::_duplicate (the_orb);
}

// Return the index of the property whose name matches the specified property.
int
CF__PropertySet_impl::index (CF::DataType & prop)
{
  return GetPropertyIndex (prop.id);
} // end of CF__PropertySet_impl::index(CF::DataType)

int
CF__PropertySet_impl::GetPropertyIndex (const char * property_name)
{
  map<string, int>::iterator m_i;
  string temp_name (property_name);

  m_i = m_property_index_mapping.find (temp_name);

  if (m_i == m_property_index_mapping.end()) {
    return -1;
  }

  return m_i->second;
} // End of GetPropertyIndex()

template <class T>
int
SetPropValue (int index,
	      const T & value,
	      CF::Properties & props,
	      CORBA::TCKind corba_data_type)
{
  if (index >= (int) props.length()) {
    return -1;
  }

  CF::DataType & prop_to_modify = props[index];
  CORBA::TypeCode_var prop_type = prop_to_modify.value.type();

  if (prop_type->kind() != corba_data_type) {
    return -1;
  }

  prop_to_modify.value <<= value;
  return 0;
} // End of SetPropValue Template

template <class T>
int
GetPropValue (int index,
	      T * value,
	      CF::Properties & props,
	      CORBA::TCKind corba_data_type)
{
  if (index >= (int) props.length()) {
    return -1;
  }

  CF::DataType & prop_to_modify = props[index];
  CORBA::TypeCode_var prop_type = prop_to_modify.value.type ();

  if (prop_type->kind () != corba_data_type) {
    return -1;
  }

  prop_to_modify.value >>= *value;
  return 0;
} // End of GetPropValue Template

int
CF__PropertySet_impl::SetPropertyValue (int index,
					const CORBA::Boolean value)
{
  if (index >= (int) m_props.length()) {
    return -1;
  }

  CF::DataType & prop_to_modify = m_props[index];
  CORBA::TypeCode_var prop_type = prop_to_modify.value.type ();

  if (prop_type->kind() != CORBA::tk_boolean) {
    return -1;
  }

  prop_to_modify.value <<= CORBA::Any::from_boolean (value);
  return 0;
}

int
CF__PropertySet_impl::SetPropertyValue (int index, const CORBA::Char value)
{
  if (index >= (int) m_props.length()) {
    return -1;
  }

  CF::DataType & prop_to_modify = m_props[index];
  CORBA::TypeCode_var prop_type = prop_to_modify.value.type ();

  if (prop_type->kind() != CORBA::tk_char) {
    return -1;
  }

  prop_to_modify.value <<= CORBA::Any::from_char (value);
  return 0;
}

int
CF__PropertySet_impl::SetPropertyValue (int index, 
					const char * value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_string);
}

int
CF__PropertySet_impl::SetPropertyValue (int index,
					const CORBA::Short value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_short);
} // End of CF__PropertySet_impl::SetPropertyValue()

int
CF__PropertySet_impl::SetPropertyValue (int index, 
					const CORBA::UShort value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_ushort);
}

int
CF__PropertySet_impl::SetPropertyValue (int index, const CORBA::Long value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_long);
}

int
CF__PropertySet_impl::SetPropertyValue(int index, 
				       const CORBA::ULong value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_ulong);
}

int
CF__PropertySet_impl::SetPropertyValue (int index,
					const CORBA::Float value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_float);
}

int
CF__PropertySet_impl::SetPropertyValue (int index,
					const CORBA::Double value)
{
  return SetPropValue (index, value, m_props, CORBA::tk_double);
}

int
CF__PropertySet_impl::GetPropertyValue (int index,
					CORBA::Boolean * value)
{
  if (index >= (int) m_props.length()) {
    return -1;
  }

  CF::DataType & prop_to_modify = m_props[index];
  CORBA::TypeCode_var prop_type = prop_to_modify.value.type ();

  if (prop_type->kind() != CORBA::tk_boolean) {
    return -1;
  }

  prop_to_modify.value >>= CORBA::Any::to_boolean (*value);
  return 0;
}

int
CF__PropertySet_impl::GetPropertyValue (int index,
					CORBA::Char * value)
{
  if (index >= (int) m_props.length()) {
    return -1;
  }

  CF::DataType & prop_to_modify = m_props[index];
  CORBA::TypeCode_var prop_type = prop_to_modify.value.type ();

  if (prop_type->kind() != CORBA::tk_char) {
    return -1;
  }

  prop_to_modify.value >>= CORBA::Any::to_char (*value);
  return 0;
}

int
CF__PropertySet_impl::GetPropertyValue (int index,
					const char ** value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_string);
}

int
CF__PropertySet_impl::GetPropertyValue (int index,
					CORBA::Short * value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_short);
} // End of CF__PropertySet_impl::GetPropertyValue()

int
CF__PropertySet_impl::GetPropertyValue (int index,
					CORBA::UShort * value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_ushort);
}

int
CF__PropertySet_impl::GetPropertyValue (int index, CORBA::Long * value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_long);
}

int
CF__PropertySet_impl::GetPropertyValue (int index, CORBA::ULong * value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_ulong);
}

int
CF__PropertySet_impl::GetPropertyValue (int index, CORBA::Float * value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_float);
}

int
CF__PropertySet_impl::GetPropertyValue (int index, CORBA::Double * value)
{
  return GetPropValue (index, value, m_props, CORBA::tk_double);
}
